# Usage: compile.tcl [-?] [-p] [-t] [--] [variant ...]

package require DPeye

cd [file dirname [info script]]
if {![info exists eDPeyeToolsDir]} {set eDPeyeToolsDir "."}
if {![info exists eOutputDir]} {set eOutputDir "../../HGjudge/DPjudge/maps"}
if {![info exists eTrialOutputDir]} {set eTrialOutputDir "../../HGjudge/DPjudge/trials"}
if {![info exists eVariantDir]} {set eVariantDir "../variants"}
if {![info exists eWorkingDir]} {set eWorkingDir "$eVariantDir/<dir>"}
if {![info exists eTestDir]} {set eTestDir $eWorkingDir}
if {![info exists ePSInfoFile]} {set ePSInfoFile [file join $eOutputDir "psinfo"]}
if {![info exists eTrialPSInfoFile]} {set eTrialPSInfoFile [file join $eTrialOutputDir "psinfo"]}
if {![info exists eTestMark]} {set eTestMark ".test"}

namespace eval Compile {

	proc mention {error {info {}}} {
		puts "Error: $error"
		if {[llength $info]} {
			puts [join $info "\n"]
		}
		return 0
	}
	
	proc readFile {fileName} {
		set fin [open $fileName r]
		set contents [read $fin]
		close $fin
		return $contents
	}
	
	proc writeFile {fileName contents} {
		set fout [open $fileName w]
		puts -nonewline $fout $contents
		close $fout
	}
	
	proc copyFile {inFileName outFileName} {
		set fin [open $inFileName r]
		set fout [open $outFileName w]
		fconfigure $fout -translation lf
		fcopy $fin $fout
		close $fout
		close $fin
	}
	
	proc parseDir {dir variantName variantDir} {
		return [absolve [regsub -all "<dir>" [regsub -all "<name>" $dir $variantName] $variantDir] [pwd]]
	}
	
	proc compile {namePatterns {publish 0} {test 0}} {
		global eOutputDir eTrialOutputDir eVariantDir eWorkingDir eTestDir ePSInfoFile eTrialPSInfoFile eTestMark
		global eWorkDir

		if {$test} {
			namespace eval :: {
				source $eDPeyeToolsDir/map2eye.tcl
				source $eDPeyeToolsDir/process.tcl
			}
		}

		if {![llength $namePatterns]} {
			set namePatterns "*"
		}
		
		set variants [iarray::Sequence #auto]
		foreach {dir scripts} [readFile [file join $eVariantDir variants]] {
			foreach script $scripts {
				if {[set unpublish [string equal -length 1 $script "!"]]} {
					set script [string range $script 1 end]
				}
				if {[set trial [string equal -length 1 $script "*"]]} {
					set script [string range $script 1 end]
				}
				$variants set $script [iarray::Array #auto dir $dir \
					script "$script.tcl" output "$script.ps" \
					map "$script.map" trial $trial unpublish $unpublish]
			}
		}
		
		foreach {name specs} [eval concat [lapply $namePatterns {$variants get}]] {
			inform "Variant: $name"
			# Compile
			set eWorkDir [parseDir $eWorkingDir $name [$specs of dir]]
			# For locationTypes we only override Supplies and Territories, not e.g. OffBoardBoxes
			# That's because the latter is optional, and if included, the OffBoardBoxes functions
			# would be generated, even if there are no off board boxes in the variant.
			set psInfo [namespace eval :: create \
				sourceFile [$specs of script] \
				addPage 0 \
				composed 0 \
				printLayout 0 \
				printPSInfo 0 \
				testBorder 0 \
				drawLayoutBorder 0 \
				locationTypes [list {
					Supplies {number 0 name 0 draw 1 define -1}
					Territories {number 0 name 1 populate 0 info 1}
				}] \
			]
			assert {[llength $psInfo] && [string equal $name [lindex $psInfo 0]]} {
				Variant name <$name> differs from ps info <$psInfo>. 
			}
		
			# Publish
			if {$publish && ![$specs of unpublish]} {
				set trial [expr [$specs of trial]?"Trial":""]
				copyFile [file join $eWorkDir [$specs of output]] [file join [set e${trial}OutputDir] [$specs of output]]
				copyFile [file join $eWorkDir [$specs of map]] [file join [set e${trial}OutputDir] [$specs of map]]
				set I [iexpect::Expect #auto -white -file [set e${trial}PSInfoFile]]
				set psInfoFileContents {}
				set found 0
				$I expect line "^#" {
					lappend psInfoFileContents [$I get output]
					$I continue
				} "^(\\S+)" {
					if {[string equal $name [$I get match 1]]} {
						assert {!$found} {
							Variant <$name> has its ps info specified twice.
						}
						set found 1
						lappend psInfoFileContents $psInfo
						if {![string equal $psInfo [$I get output]]} {
							inform "Replacing ps info <[$I get output]> with <$psInfo>."
							set found 2
						}
					} else {
						lappend psInfoFileContents [$I get output]
					}
					$I continue
				} default {
					lappend psInfoFileContents [$I get output]
					$I continue
				}
				itcl::delete object $I
				if {!$found} {
					inform "Adding ps info <$psInfo>."
					set found 3
					lappend psInfoFileContents $psInfo
				}
				if {$found > 1} {
					writeFile [set e${trial}PSInfoFile] [join $psInfoFileContents "\n"]
				}
			}
			
			# Test
			if {$test} {
				set testFile [file join [parseDir $eTestDir $name [$specs of dir]] "$name$eTestMark.txt"]
				if {![file exists $testFile]} {
					inform "Creating test file <$testFile>."
					Map2Eye::map2eye [file join $eWorkDir "$name.map"] $testFile
				}
				Process::process [file join $eWorkDir "$name.ps"] $testFile
			}
		}
		
	}

}

if {[llength $argv]} {
	set eHelpInfo {
	 	"Usage: compile.tcl [-?] [-p] [-t] [--] [variant ...]"
		."Each variant may be a glob-style name, that is it can contain * and ? to match more than one variant name."
		"By default compiles every known variant."
		"\t-?: Display this help message"
		"\t-p: Publish"
		"\t-t: (Re)make test file"
		"\t--: No more switches to follow"
	}

	set publish 0
	set test 0

	while {[llength $argv] && [regexp "^\[-/\](.)$" [lindex $argv 0] switching swi]} {
		set argv [lrange $argv 1 end]
		switch -- $swi ? {
			puts [join $eHelpInfo "\n"]
			exit
		} p {
			set publish 1
		} t {
			set test 1
		} - {
			break
		} default {
			mention "Switch <$swi> not supported." $eHelpInfo 
			exit
		}
	}

	set arguments $argv
	set argv {}
	
	Compile::compile $arguments $publish $test
}